#ifndef DATABASEMANAGER_H
#define DATABASEMANAGER_H

#include <QObject>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QPair>
#include <QVector>
#include <tuple>
#include <QTcpSocket>
#include <QHostAddress>
#include <QEventLoop>
#include <QTimer>
#include <QMutex>

class DatabaseManager:public QObject
{
    Q_OBJECT
public:
    static DatabaseManager& getInstance();
    QSqlDatabase getDatabase() const;
    int insert_register(const QString& nickname,const QString& password,const QString &phone,const QString& email);
    std::tuple<QString,QString,QString> query_login(const QString& username,const QString& password);
    std::tuple<QString,QString,QString> query_login(const QString& username);
    bool close_login(const QString &username);
    bool CloseUserStatus(const QString &username);
    QVector<std::tuple<QString,QString,QString>> query_path(const QString& id);
    QVector<std::tuple<QString,QString,QString,int>> query_request(const QString& id,const QString& goal=nullptr);
    QVector<std::tuple<QString,QString,QString,int>> query_send_request(const QString& id,const QString& goal=nullptr);
    bool PrivateSendMsg(const QString &id_1,const QString &id_2,const QString& text );
    QVector<QString> PrivateGetMsg(const QString& id_1,const QString& id_2,const QString &last_time);
    int insert_request_or_member(int chat_type,int scale,const QString &id_1,const QString &id_2,const int type);
    void recvServerMsg();
    void OnlineMsg(const QString& sender_id,const QString &receiver_id,const QString &msg_type,const QString &content,const QString&
                media_url,const QString &send_time,const QString &is_deleted);
    void OnlineReq(const QString &id,const QString& user1,const QString &user2,const QString  &user1_last_read_time,const QString user2_last_read_time,
                const QString& who_request,const QString &relationship_type,const QString& create_time,const QString& update_time,
                const QString &text_count);
    bool sendToServer(const QString& data);
    // 模板函数：通用发送接口（声明在.h中）
    template<typename... Args>
    bool send(const QString& funcName, Args&&... args);
    template<typename T>//因为要自动推导类型，所以必须把实现放在这里
    QString convertArg(T&& arg) {
        // 对于基本类型，如int、double等，可使用QString的转换函数
        if constexpr (std::is_integral_v<std::remove_reference_t<T>>) {
            return QString::number(std::forward<T>(arg));
        } else if constexpr (std::is_floating_point_v<std::remove_reference_t<T>>) {
            return QString::number(std::forward<T>(arg));
        } else if constexpr (std::is_same_v<std::remove_reference_t<T>, QString> ||
                             std::is_same_v<std::remove_reference_t<T>, const QString>) {
            qDebug()<<"arg="<<arg;
            return std::forward<T>(arg);
        } else if constexpr (std::is_same_v<std::remove_reference_t<T>, const char*>) {
            return QString::fromUtf8(std::forward<T>(arg));
        } else {
            // 对于自定义类型等，可根据实际情况进行转换
            // 这里简单处理为返回空字符串，实际应按需实现
            qDebug() << "默认分支，类型为：" << typeid(std::remove_reference_t<T>).name();
            return QString();
        }
    }
    // bool block(const QString& key, int timeoutMs);
private:
    DatabaseManager();
    ~DatabaseManager();
    DatabaseManager(const DatabaseManager& )=delete;
    DatabaseManager& operator=(const DatabaseManager&) =delete;
    QTcpSocket* socket;
    QSqlDatabase db;
    QByteArray m_receiveBuffer;
    // std::unordered_map<QString, std::function<void(const QVector<QString>&)>> msgFuncMap;

    QMap<QString, QEventLoop*> m_eventLoops; // 存储事件循环，key为操作标识
    QMap<QString, QTimer*> m_timers; // 存储定时器，key为操作标识
    QMutex m_blockMutex; // 用于保护上述两个映射的互斥锁

    QMap<QString, QVariant> m_results; // 存储操作结果
    QMutex m_resultMutex; // 保护结果的互斥锁

    QString generateOperationId(const QString& funcName, const QVector<QString>& params);
    // 开始阻塞
    void startBlocking(const QString& operationId, int timeoutMs);
    // 解除阻塞
    void stopBlocking(const QString& operationId);

    // 设置结果
    void setResult(const QString& operationId, const QVariant& result);
    // 获取结果并转换为目标类型
    template<typename T>
    T getResult(const QString& operationId);
};

#endif // DATABASEMANAGER_H
